package com.fowo.api.syncAmazon.core.sync;

import cn.hutool.core.collection.ListUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.amazon.spapi.model.reports.CreateReportSpecification;
import com.amazon.spapi.model.reports.Report;
import com.amazon.spapi.model.reports.ReportDocument;
import com.amazon.spapi.model.reports.ReportOptions;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.fowo.api.entity.ListingFather;
import com.fowo.api.entity.ShopInfo;
import com.fowo.api.entity.TmpBusinessReportsByChild;
import com.fowo.api.service.impl.ListingFatherServiceImpl;
import com.fowo.api.service.impl.ShopInfoServiceImpl;
import com.fowo.api.service.impl.TmpBusinessReportsByChildServiceImpl;
import com.fowo.api.syncAmazon.core.AbstractAmazonSyncData;
import com.fowo.api.syncAmazon.core.ReportApiType;
import com.fowo.api.syncAmazon.entity.ApiDefine;
import com.fowo.api.syncAmazon.entity.ApiRequestLog;
import com.fowo.api.syncAmazon.mapper.AmazonTmpMapper;
import com.fowo.api.syncAmazon.util.AmzDateUtils;
import com.fowo.api.syncAmazon.util.GeneralUtil;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.io.BufferedReader;
import java.io.IOException;
import java.math.BigDecimal;
import java.time.ZoneId;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @fileName: BusinessReportBySku
 * @Description: 代码目的，作用，如何工作
 * @Author: yyf
 * @Date: 2024/2/23 0023 13:38
 */
@Component
public class BusinessReportByChild extends AbstractAmazonSyncData {
    @Resource
    private AmazonTmpMapper amazonTmpMapper;
    @Resource
    private ShopInfoServiceImpl shopInfoServiceImpl;
    @Resource
    private TmpBusinessReportsByChildServiceImpl tmpBusinessReportsByChildService;
    private ApiDefine apiDefine = ApiDefine.builder()
            .apiCode("business_report_by_child")
            .initdate(30)
            .timeInterval(1)
            .timeIntervalType("day").build();

    @Override
    protected ApiDefine setApiDefine() {
        return apiDefine;
    }

    @Override
    protected void requestData() throws Exception {
        // 获取卖家账号信息
        String platform = "Amazon";
        this.getAuthority(platform);
        // 查询该账号下所有店铺
        LambdaQueryWrapper<ShopInfo> shopInfosWrapper = new LambdaQueryWrapper<>();
        shopInfosWrapper.eq(ShopInfo::getPlatform,"Amazon")
                .eq(ShopInfo::getSellerAuthStatus,"SQ01");
        List<ShopInfo> shopInfoList = shopInfoServiceImpl.list(shopInfosWrapper);
        // 清空临时表
        amazonTmpMapper.deleteTmpBusinessReportsByChild();

        //请求报告
        for (ShopInfo shopInfo : shopInfoList) {
            //创建报告 -查询参数
            List<String> marketplaceIds = Arrays.asList(shopInfo.getMarketplaceId().split(","));
            CreateReportSpecification body = new CreateReportSpecification();
            body.setReportType(ReportApiType.GET_SALES_AND_TRAFFIC_REPORT);
            body.setMarketplaceIds(marketplaceIds);
            ReportOptions reportOptions = new ReportOptions();
            reportOptions.put("dateGranularity","DAY");
            reportOptions.put("asinGranularity","CHILD");
            body.setReportOptions(reportOptions);

            // 获取拉取的时间区间
            body.setDataStartTime(AmzDateUtils.getOffsetDateTimeUTC(startTime));
            body.setDataEndTime(AmzDateUtils.getOffsetDateTimeUTC(endTime));

            // 第一步 创建报告
            final String reportId = retryCreateReport(shopInfo, body);
            // 第二步 检验报告是否完成
            Report report = retryCheckReport(shopInfo, reportId);
            // 第三步 获取报告连接
            ReportDocument reportDocument = getReportDocument(shopInfo,report.getReportDocumentId());
            System.out.println(reportDocument.getUrl());

            if (reportDocument != null) {
                String compressionAlgorithm = reportDocument.getCompressionAlgorithm() != null ? reportDocument.getCompressionAlgorithm().getValue() : null;
                BufferedReader reader = this.getAndUnzipReport(reportDocument.getUrl(), compressionAlgorithm);
                try {
                    download(reader, shopInfo);
                }catch (Exception ex){
                    throw new RuntimeException(ex);
                }finally {
                    reader.close();
                }
            }
        }
    }

    @Override
    protected <T> void download(T param, ShopInfo shop) throws IOException, IllegalArgumentException {
        BufferedReader reader = null;
        if (param instanceof BufferedReader){
            try {
                reader = (BufferedReader)param;
            }catch (Exception e){
                throw new RuntimeException(e);
            }
        }

        String line;
        String amount = "amount";
        String currencyCode = "currencyCode";
        List<TmpBusinessReportsByChild> tmpData = new ArrayList<>();

        while ((line = reader.readLine()) != null){
            JSONObject json = GeneralUtil.getJsonObject(line);
            JSONObject reportSpecification = json.getJSONObject("reportSpecification");
            JSONArray salesAndTrafficByDate = json.getJSONArray("salesAndTrafficByDate");
            JSONArray salesAndTrafficByAsin = json.getJSONArray("salesAndTrafficByAsin");

            reportSpecification.getString("reportType");
            JSONObject reportOptions = reportSpecification.getJSONObject("reportOptions");
            reportOptions.getString("dateGranularity");
            reportOptions.getString("asinGranularity");
            Date dataTime = Date.from(startTime.toInstant().atZone(ZoneId.systemDefault()).toLocalDate()
                    .atStartOfDay().atZone(ZoneId.systemDefault()).toInstant());
            reportSpecification.getDate("dataEndTime");
            reportOptions.getJSONArray("marketplaceIds");

            for (int i = 0; i < salesAndTrafficByDate.size(); i++) {
                JSONObject jsonObject = salesAndTrafficByDate.getJSONObject(i);
                jsonObject.getDate("date");

                JSONObject salesByDate = jsonObject.getJSONObject("salesByDate");
                JSONObject orderdProductSales = salesByDate.getJSONObject("orderedProductSales");
                orderdProductSales.getBigDecimal(amount);
                orderdProductSales.getString(currencyCode);
                salesByDate.getInteger("unitsOrdered");
                salesByDate.getInteger("totalOrderItems");
                JSONObject averageSalesPerOrderItem = salesByDate.getJSONObject("averageSalesPerOrderItem");
                averageSalesPerOrderItem.getBigDecimal(amount);
                averageSalesPerOrderItem.getString(currencyCode);
                salesByDate.getDouble("averageUnitsPerOrderItem");
                JSONObject averageSellingPrice = salesByDate.getJSONObject("averageSellingPrice");
                averageSellingPrice.getBigDecimal(amount);
                averageSellingPrice.getString(currencyCode);
                salesByDate.getInteger("unitsRefunded");
                salesByDate.getDouble("refundRate");
                salesByDate.getInteger("claimsGranted");
                JSONObject claimsAmount = salesByDate.getJSONObject("claimsAmount");
                claimsAmount.getBigDecimal(amount);
                claimsAmount.getString(currencyCode);
                JSONObject shippedProductSales = salesByDate.getJSONObject("shippedProductSales");
                shippedProductSales.getBigDecimal(amount);
                shippedProductSales.getString(currencyCode);
                salesByDate.getInteger("unitsShipped");
                salesByDate.getInteger("ordersShipped");

                JSONObject trafficByDate = jsonObject.getJSONObject("trafficByDate");
                trafficByDate.getInteger("browserPageViews");
                trafficByDate.getInteger("mobileAppPageViews");
                trafficByDate.getInteger("pageViews");
                trafficByDate.getInteger("browserSessions");
                trafficByDate.getInteger("mobileAppSessions");
                trafficByDate.getInteger("sessions");
                trafficByDate.getDouble("buyBoxPercentage");
                trafficByDate.getDouble("orderItemSessionPercentage");
                trafficByDate.getDouble("unitSessionPercentage");
                trafficByDate.getInteger("averageOfferCount");
                trafficByDate.getInteger("averageParentItems");
                trafficByDate.getInteger("feedbackReceived");
                trafficByDate.getInteger("negativeFeedbackReceived");
                trafficByDate.getDouble("receivedNegativeFeedbackRate");

            }

            for (int i = 0; i < salesAndTrafficByAsin.size(); i++) {
                TmpBusinessReportsByChild tmp = new TmpBusinessReportsByChild();
                tmp.setCreateTime(new Date());
                tmp.setLastUpdateTime(new Date());
                tmp.setSid(shop.getId());

                JSONObject jsonObject = salesAndTrafficByAsin.getJSONObject(i);
                tmp.setParentAsin(jsonObject.getString("parentAsin"));
                tmp.setChildAsin(jsonObject.getString("childAsin"));
                tmp.setDataTime(dataTime);

                JSONObject salesByAsin = jsonObject.getJSONObject("salesByAsin");
                tmp.setUnitsOrdered(salesByAsin.getInteger("unitsOrdered"));
                tmp.setUnitsOrderedB2b(salesByAsin.getInteger("unitsOrderedB2B"));
                JSONObject orderdProductSales = salesByAsin.getJSONObject("orderedProductSales");
                tmp.setOrderedProductSales(orderdProductSales.getBigDecimal(amount));
                tmp.setCurrency(orderdProductSales.getString(currencyCode));
                JSONObject orderdProductSalesB2B = salesByAsin.getJSONObject("orderdProductSalesB2B");
                if(orderdProductSalesB2B != null){
                    tmp.setOrderedProductSalesB2b(orderdProductSalesB2B.getBigDecimal(amount));
                    tmp.setCurrency(orderdProductSalesB2B.getString(currencyCode));
                }else {
                    tmp.setOrderedProductSalesB2b(BigDecimal.ZERO);
                }

                tmp.setTotalOrderItems(salesByAsin.getInteger("totalOrderItems"));
                tmp.setTotalOrderItemsB2b(salesByAsin.getInteger("totalOrderItemsB2B"));

                JSONObject trafficByAsin = jsonObject.getJSONObject("trafficByAsin");
                tmp.setBrowserSessions(trafficByAsin.getInteger("browserSessions"));
                tmp.setBrowserSessionsB2b(trafficByAsin.getInteger("browserSessionsB2B"));
                tmp.setBrowserPageViews(trafficByAsin.getInteger("browserPageViews"));
                tmp.setBrowserPageViewsB2b(trafficByAsin.getInteger("browserPageViewsB2B"));
                tmp.setMobileAppSessions(trafficByAsin.getInteger("mobileAppSessions"));
                tmp.setMobileAppSessionsB2b(trafficByAsin.getInteger("mobileAppSessionsB2B"));
                tmp.setSessions(trafficByAsin.getInteger("sessions"));
                tmp.setSessionsB2b(trafficByAsin.getInteger("sessionsB2B"));
                tmp.setBrowserSessionPercentage(trafficByAsin.getBigDecimal("browserSessionPercentage"));
                tmp.setBrowserSessionPercentageB2b(trafficByAsin.getBigDecimal("browserSessionPercentageB2B"));
                tmp.setMobileAppSessionPercentage(trafficByAsin.getBigDecimal("mobileAppSessionPercentage"));
                tmp.setMobileAppSessionPercentageB2b(trafficByAsin.getBigDecimal("mobileAppSessionPercentageB2B"));
                tmp.setSessionPercentage(trafficByAsin.getBigDecimal("sessionPercentage"));
                tmp.setSessionPercentageB2b(trafficByAsin.getBigDecimal("sessionPercentageB2B"));
                tmp.setBrowserPageViews(trafficByAsin.getInteger("browserPageViews"));
                tmp.setBrowserPageViewsB2b(trafficByAsin.getInteger("browserPageViewsB2B"));
                tmp.setMobileAppPageViews(trafficByAsin.getInteger("mobileAppPageViews"));
                tmp.setMobileAppPageViewsB2b(trafficByAsin.getInteger("mobileAppPageViewsB2B"));
                tmp.setPageViews(trafficByAsin.getInteger("pageViews"));
                tmp.setPageViewsB2b(trafficByAsin.getInteger("pageViewsB2B"));
                tmp.setBrowserPageViewsPercentage(trafficByAsin.getBigDecimal("browserPageViewsPercentage"));
                tmp.setBrowserPageViewsPercentageB2b(trafficByAsin.getBigDecimal("browserPageViewsPercentageB2B"));
                tmp.setMobileAppPageViewsPercentage(trafficByAsin.getBigDecimal("mobileAppPageViewsPercentage"));
                tmp.setMobileAppPageViewsPercentageB2b(trafficByAsin.getBigDecimal("mobileAppPageViewsPercentageB2B"));
                tmp.setPageViewsPercentage(trafficByAsin.getBigDecimal("pageViewsPercentage"));
                tmp.setPageViewsPercentageB2b(trafficByAsin.getBigDecimal("pageViewsPercentageB2B"));
                tmp.setBuyBoxPercentage(trafficByAsin.getBigDecimal("buyBoxPercentage"));
                tmp.setBuyBoxPercentageB2b(trafficByAsin.getBigDecimal("buyBoxPercentageB2B"));
                tmp.setUnitSessionPercentage(trafficByAsin.getBigDecimal("unitSessionPercentage"));
                tmp.setUnitSessionPercentageB2b(trafficByAsin.getBigDecimal("unitSessionPercentageB2B"));

                tmpData.add(tmp);
            }
        }
        // 跟listingfather关联
        logger.info("--跟listingfather关联--");
        getIdFromListingFather(tmpData,shop);

        // 写入同步数据量
        Integer dataVolume = apiRequestLog.getDataVolume() == null ? 0 : apiRequestLog.getDataVolume();
        apiRequestLog.setDataVolume(dataVolume+tmpData.size());

        tmpBusinessReportsByChildService.saveBatch(tmpData);

    }

    @Override
    protected void updateOrInsertData() {
        logger.info("--正在更新或新增--");
        amazonTmpMapper.updateTmpBusinessReportsByChild();
        amazonTmpMapper.insertTmpBusinessReportsByChild();
    }

    @Resource
    private ListingFatherServiceImpl listingFatherService;
    private void getIdFromListingFather(List<TmpBusinessReportsByChild> lists, ShopInfo shopInfo){
        if(lists == null || lists.size() == 0){
            return;
        }
        // 按asin做关联
        List<ListingFather> listingFather = new ArrayList<>();
        for (List<TmpBusinessReportsByChild> tmpSellOrderDetails : ListUtil.partition(lists, 500)) {
            List<String> asins = tmpSellOrderDetails.stream().map(TmpBusinessReportsByChild::getChildAsin).collect(Collectors.toList());
            List<ListingFather> tmp = listingFatherService.list(Wrappers.lambdaQuery(ListingFather.class).eq(ListingFather::getShop, shopInfo.getId())
                    .in(ListingFather::getAsin, asins));
            listingFather.addAll(tmp);
        }

        for (TmpBusinessReportsByChild list : lists) {
            List<ListingFather> collect = listingFather.stream().filter(r -> r.getAsin().equals(list.getChildAsin())).collect(Collectors.toList());
            if (collect != null && collect.size() > 0){
                Optional<ListingFather> exist1 = collect.stream().filter(r -> r.getStatus().equals(1)).findFirst();
                Optional<ListingFather> exist2 = collect.stream().filter(r -> r.getStatus().equals(0)).findFirst();
                if (exist1.isPresent()){
                    list.setInnerLID(exist1.get().getId());
                }else if(exist2.isPresent()){
                    list.setInnerLID(exist2.get().getId());
                }else{
                    list.setInnerLID(collect.get(0).getId());
                }
            }
        }
    }
}
